﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace August.UI
{
    public class Rectancle : ShapeBase
    {
        private PointF m_mouseDownRotatePoint;
        private bool m_isrotate = false;
        private int scaleType = -1;
        internal GraphicsPath RotateGraphicPath = new GraphicsPath();
        public GraphicsPath ScaleGraphicPathW = new GraphicsPath();
        public GraphicsPath ScaleGraphicPathH = new GraphicsPath();
        public float Width;
        public float Height;
        public float Angle;
        private PointF[] lastPointWithOutRotate=new PointF[5];
        public Rectancle(float centerx, float centery, float width, float height, float angle)
        {
            PointFs = new System.Drawing.PointF[5];
            PointFs[0].X = centerx;
            PointFs[0].Y = centery;

            Width = width;
            Height = height;
            Angle = angle;
        }

        internal override bool OnDownPaint(MouseEventArgs e)
        {
            m_mouseDownRotatePoint = PointFs[3];
            scaleType = -1;
            m_IsScale = false;
            m_IsSelectedPoint = false;
            m_isrotate = false;
            if (this.DrawGraphicsPath.IsOutlineVisible(e.X, e.Y, new Pen(Color.Empty, DrawLineWidth + 6)))
            {
                m_isSelected = true;
                m_DrawColor = ShapeBase.ColorMouseDown;
                m_mouseDownMovePointFs = new PointF[PointFs.Length];
                PointFs.CopyTo(m_mouseDownMovePointFs, 0);
                if (MoveGraphicPath.IsOutlineVisible(e.X, e.Y, new Pen(Color.Empty, DrawLineWidth + 6)))
                {
                    m_IsSelectedPoint = true;
                }
                if (RotateGraphicPath.IsOutlineVisible(e.X, e.Y, new Pen(Color.Empty, DrawLineWidth + 6)))
                {
                    m_isrotate = true;
                }
                else if (ScaleGraphicPathW.IsOutlineVisible(e.X, e.Y, new Pen(Color.Empty, DrawLineWidth + 6)))
                {
                    m_IsScale = true;
                    scaleType = 0;
                }
                else if (ScaleGraphicPathH.IsOutlineVisible(e.X, e.Y, new Pen(Color.Empty, DrawLineWidth + 6)))
                {
                    m_IsScale = true;
                    scaleType = 1;
                }
                return true;
            }
            else
                return false;
        }

        internal override void OnMovePaint(MouseEventArgs e)
        {
            base.OnMovePaint(e);
            if (m_isSelected && IsUserShape)
            {
                if (m_IsSelectedPoint)
                {
                    Point point = e.Location;
                    Matrix matrix = new Matrix();
                    matrix.Translate((-m_mouseDownPointF.X + point.X) * 1f / Parent.Owner.ScaleX, (-m_mouseDownPointF.Y + point.Y) * 1f / Parent.Owner.ScaleY);
                    m_mouseDownMovePointFs.CopyTo(PointFs, 0);
                    PointF[] pointFsSelect = new PointF[5] { PointFs[0], PointFs[1], PointFs[2], PointFs[3], PointFs[4] };
                    matrix.TransformPoints(pointFsSelect);
                    PointFs = pointFsSelect;
                }
                else if (m_isrotate)
                {
                    float v = 1f;
                    double ang = 0d;
                    Point point = e.Location;
                    double[] distances = GetDistance(new PointF[3] { LastPointFs[0], lastPointWithOutRotate[3], new PointF(point.X, point.Y) }, new PointF[3] { lastPointWithOutRotate[3], new PointF(point.X, point.Y), LastPointFs[0] });
                    double kl = (lastPointWithOutRotate[3].Y - LastPointFs[0].Y) / (lastPointWithOutRotate[3].X - LastPointFs[0].X);
                    double bl = LastPointFs[0].Y - kl * LastPointFs[0].X;
                    if (point.Y < point.X * kl + bl)
                    {
                        v = -1f;
                    }
                    else
                    {
                        v = 1f;
                    }
                    double a = distances[0];
                    double b = distances[2];
                    double c = distances[1];
                    ang = Math.Acos((Math.Pow(a, 2) + Math.Pow(b, 2) - Math.Pow(c, 2)) / (2 * a * b))/Math.PI*180;
                    Angle = (float)ang * v;
                   // Console.WriteLine(LastPointFs[0].ToString() + "  " + lastPointWithOutRotate[3].ToString() + "  " + new PointF(point.X, point.Y) + "  " + a + ";" + b + ";" + c + "  " + Angle);
                }
                else if (m_IsScale)
                {
                    Point point = e.Location;
                    Matrix matrix = new Matrix();
                    matrix.RotateAt(0 - Angle, LastPointFs[0]);
                    PointF[] pointFs = new PointF[1] { new PointF(point.X, point.Y) };
                    matrix.TransformPoints(pointFs);
                    if (scaleType == 1)
                    {
                        float offx = Math.Abs(pointFs[0].X - LastPointFs[0].X) * 1f / Parent.Owner.ScaleX;
                        Width = offx * 2;
                    }
                    else if (scaleType == 0)
                    {
                        float offy = Math.Abs(pointFs[0].Y - LastPointFs[0].Y) * 1f / Parent.Owner.ScaleY;
                        Height = offy * 2;
                    }
                }
            }
        }
        private double[] GetDistance(PointF[] pointA, PointF[] pointB)
        {
            if (pointA.Length != pointB.Length) throw new Exception("getDistance : point length not equal");
            double[] distances = new double[pointA.Length];
            for (int i = 0; i < distances.Length; i++)
            {
                distances[i] = Math.Pow((pointA[i].X - pointB[i].X), 2) + Math.Pow((pointA[i].Y - pointB[i].Y), 2);
                distances[i] = Math.Sqrt(distances[i]);
            }
            return distances;
        }

        internal override void OnWheelPaint(PaintEventArgs e)
        {
            Rectancle rect = this;
            PointFs[1].X = PointFs[0].X - Width / 2;
            PointFs[1].Y = PointFs[0].Y - Height / 2;
            PointFs[2].X = PointFs[0].X + Width / 2;
            PointFs[2].Y = PointFs[0].Y - Height / 2;
            PointFs[3].X = PointFs[0].X + Width / 2;
            PointFs[3].Y = PointFs[0].Y + Height / 2;
            PointFs[4].X = PointFs[0].X - Width / 2;
            PointFs[4].Y = PointFs[0].Y + Height / 2;
            PointF[] m_pointFs = new PointF[PointFs.Length];
            PointF[] m_lastPointWithOutRotate = new PointF[PointFs.Length];
            PointFs.CopyTo(m_pointFs, 0);
            PointFs.CopyTo(m_lastPointWithOutRotate, 0);
            float wid = rect.Width;
            float hei = rect.Height;
            using (System.Drawing.Drawing2D.Matrix transform = new Matrix())
            {
                transform.Scale(Parent.Owner.ScaleX, Parent.Owner.ScaleY, System.Drawing.Drawing2D.MatrixOrder.Append);
                transform.Translate(Parent.Owner.OffsetX, Parent.Owner.OffsetY, System.Drawing.Drawing2D.MatrixOrder.Append);
                transform.TransformPoints(m_lastPointWithOutRotate);
                lastPointWithOutRotate = m_lastPointWithOutRotate;
                transform.RotateAt(Angle, m_pointFs[0]);
                transform.TransformPoints(m_pointFs);
                wid = wid * Parent.Owner.ScaleX;
                hei = hei * Parent.Owner.ScaleY;
                rect.TransForm = transform.Clone();
                rect.LastPointFs = m_pointFs;
            }
            GraphicsPath graphicsPath = new GraphicsPath();
            graphicsPath.AddLine(m_pointFs[1], m_pointFs[2]);
            graphicsPath.AddLine(m_pointFs[2], m_pointFs[3]);
            graphicsPath.AddLine(m_pointFs[3], m_pointFs[4]);
            graphicsPath.AddLine(m_pointFs[4], m_pointFs[1]);
            graphicsPath.AddPath(CreateCrossGraphicPath(m_pointFs[0], 6, 0), false);
            rect.DrawGraphicsPath = graphicsPath;
            rect.DrawRegion = new Region(graphicsPath);
            e.Graphics.DrawPath(new Pen(rect.m_DrawColor, rect.DrawLineWidth), graphicsPath);
            rect.MoveGraphicPath = CreateCrossGraphicPath(m_pointFs[0], 6, 0);

            GraphicsPath graphicsPathW1 = new GraphicsPath();
            graphicsPathW1.AddLine(m_pointFs[1], m_pointFs[2]);
            GraphicsPath graphicsPathW2 = new GraphicsPath();
            graphicsPathW2.AddLine(m_pointFs[3], m_pointFs[4]);
            GraphicsPath graphicsPathW = new GraphicsPath();
            graphicsPathW.AddPath(graphicsPathW1, false);
            graphicsPathW.AddPath(graphicsPathW2, false);
            rect.ScaleGraphicPathW = graphicsPathW;

            GraphicsPath graphicsPathH1 = new GraphicsPath();
            graphicsPathH1.AddLine(m_pointFs[1], m_pointFs[4]);
            GraphicsPath graphicsPathH2 = new GraphicsPath();
            graphicsPathH2.AddLine(m_pointFs[2], m_pointFs[3]);
            GraphicsPath graphicsPathH = new GraphicsPath();
            graphicsPathH.AddPath(graphicsPathH1, false);
            graphicsPathH.AddPath(graphicsPathH2, false);
            rect.ScaleGraphicPathH = graphicsPathH;

            if (IsUserShape)
            {
                GraphicsPath rotateGraphicPath = new GraphicsPath();
                //rotateGraphicPath.AddPath(CreateCrossGraphicPath(m_pointFs[1], 6, 0), false);
                //rotateGraphicPath.AddPath(CreateCrossGraphicPath(m_pointFs[2], 6, 0), false);
                rotateGraphicPath.AddPath(CreateCrossGraphicPath(m_pointFs[3], 6, 0), false);
                //rotateGraphicPath.AddPath(CreateCrossGraphicPath(m_pointFs[4], 6, 0), false);
                rect.RotateGraphicPath = rotateGraphicPath;
                e.Graphics.DrawPath(new Pen(Color.Pink, rect.DrawLineWidth), rotateGraphicPath);
            }
            Console.WriteLine(PointFs[0].ToString());
            base.OnWheelPaint(e);
        }

        private GraphicsPath CreateCrossGraphicPath(PointF pointF, float radius, float angle)
        {
            float L1x1 = pointF.X - radius;
            float L1y1 = pointF.Y;
            float L1x2 = pointF.X + radius;
            float L1y2 = pointF.Y;
            float L2x1 = pointF.X;
            float L2y1 = pointF.Y - radius;
            float L2x2 = pointF.X;
            float L2y2 = pointF.Y + radius;
            PointF[] pointFs = new PointF[4] { new PointF(L1x1, L1y1), new PointF(L1x2, L1y2), new PointF(L2x1, L2y1), new PointF(L2x2, L2y2) };
            Matrix transform = new Matrix();
            transform.RotateAt(angle, pointF);
            transform.TransformPoints(pointFs);

            GraphicsPath graphicsPath1 = new GraphicsPath();
            graphicsPath1.AddLine(pointFs[0], pointFs[1]);
            GraphicsPath graphicsPath2 = new GraphicsPath();
            graphicsPath2.AddLine(pointFs[2], pointFs[3]);
            graphicsPath1.AddPath(graphicsPath2, false);
            return graphicsPath1;
        }

    }
}
